﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using FrontEnd.Storage;
using FrontEnd.Storage.Layout;
using Tools.MAME;
using System.Diagnostics;

namespace FrontEnd
{
    ///-------------------------------------------------------------------------------------------------
    /// <summary> The main form. </summary>
    ///-------------------------------------------------------------------------------------------------
    public partial class FormMain : Form
    {
        #region Member Variables

        private FrontEndStg m_settiongs;
        private Emulator m_currentEmulator;
        private List<PictureBox> m_artworkPictureBoxes;

        #endregion

        #region Constructor

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Default constructor. </summary>
        ///-------------------------------------------------------------------------------------------------
        public FormMain()
        {
            InitializeComponent();

            m_settiongs = new FrontEndStg();
            m_currentEmulator = null;
            m_artworkPictureBoxes = new List<PictureBox>();

            //
            // Debugging
            //
            
            m_settiongs.LoadFrom(@"C:\Users\Mike\Desktop\testSettings.xml");
            m_currentEmulator = m_settiongs.Emulators[0];

            LayoutStg layout = new LayoutStg(@"C:\Users\Mike\Desktop\test\default.layout");
            LoadLayout(m_currentEmulator, layout);
        }

        #endregion

        #region Override

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Processes a command key. </summary>
        /// <param name="msg">     [in,out] A <see cref="T:System.Windows.Forms.Message" />, passed by
        /// reference, that represents the Win32 message to process. </param>
        /// <param name="keyData"> One of the <see cref="T:System.Windows.Forms.Keys" /> values that
        /// represents the key to process. </param>
        /// <returns> true if the keystroke was processed and consumed by the control; otherwise, false to
        /// allow further processing. </returns>
        ///-------------------------------------------------------------------------------------------------
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            try
            {
                if (keyData == Keys.Up)
                {
                    gameListDisplay.Decrement();
                    return true;
                }
                else if (keyData == Keys.Down)
                {
                    gameListDisplay.Increment();
                    return true;
                }
                else if (keyData == Keys.Left)
                {
                    //return true;
                }
                else if (keyData == Keys.Right)
                {
                    //return true;
                }
                else if ((keyData == (Keys.Control | Keys.Up)) ||
                    (keyData == (Keys.Control | Keys.Left)))
                {
                    //return true;
                }
                else if ((keyData == (Keys.Control | Keys.Down)) ||
                    (keyData == (Keys.Control | Keys.Right)))
                {
                    //return true;
                }
                else if (keyData == Keys.Escape)
                {
                    Close();
                    return true;
                }
                else if (keyData == Keys.Return)
                {
                    StartCurrentGame();
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
                return true;
            }

            return base.ProcessCmdKey(ref msg, keyData);
        }

        #endregion

        #region Debugging

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Generates a debug game list. </summary>
        /// <exception cref="Exception"> Thrown when an exception error condition occurs. </exception>
        ///-------------------------------------------------------------------------------------------------
        private static void GenerateDebugGameList()
        {
            using (GameDatabase mameDb = new GameDatabase())
            {
                ConnectionStatus rc = mameDb.Connect(@"C:\Users\Mike\AppData\Local\GameListEditor\Games.sqlite.db");
                if (rc != ConnectionStatus.Success)
                    throw new Exception("Invalid db.");

                DatabaseFilter filter = new DatabaseFilter();
                filter.ExcludeBootlegs = true;
                filter.ExcludeHacks = true;
                filter.ExcludeMature = true;
                filter.ExcludeNonPlayable = true;
                filter.AddSmartButtonCountFilter(7);
                filter.AddSmartPlayerCountFilter(1, 2);
                filter.AddRegion("usa");
                filter.FilterMode = IntelligentFilterMode.OnePerWithRegionHint;

                GameListStg gameListStg = new GameListStg();
                using (DataTable table = mameDb.GetData(new String[] { "gamename", "cloneof", "description" }, filter))
                    foreach (DataRow row in table.Rows)
                        gameListStg.Add(new Game((String)row[0], row.IsNull(1) ? null : (String)row[1], (String)row[2]));

                gameListStg.SaveTo(@"C:\Users\Mike\Desktop\test\oneper.gamelist");
            }
        }

        private static void GenerateDebugSettingsFile()
        {
            Emulator mameEmulator = new Emulator();

            mameEmulator.ExecutablePath = @"C:\Program Files Not Installed\Mame 152\mame.exe";
            mameEmulator.RomPath = @"M:\Roms\MAME\roms";
            mameEmulator.DataFolderName = "test";

            mameEmulator.ArtworkFolderPaths.Add("C:\\Program Files Not Installed\\Mame 152\\flyers", ArtworkType.Flyer);
            mameEmulator.ArtworkFolderPaths.Add("C:\\Program Files Not Installed\\Mame 152\\marquees", ArtworkType.Marquee);
            mameEmulator.ArtworkFolderPaths.Add("C:\\Program Files Not Installed\\Mame 152\\snap", ArtworkType.Snap);
            mameEmulator.ArtworkFolderPaths.Add("C:\\Program Files Not Installed\\Mame 152\\cpanel", ArtworkType.ControlPanel);

            FrontEndStg frontEndStg = new FrontEndStg();
            frontEndStg.Emulators.Add(mameEmulator);
            frontEndStg.SaveTo(@"C:\Users\Mike\Desktop\testSettings.xml");
        }

        private static void GenerateDebugLayout()
        {
            LayoutStg layoutStg = new LayoutStg();

            ArtworkDefinition flyers = new ArtworkDefinition();
            flyers.ArtworkType = ArtworkType.Flyer;
            flyers.Location = new Point(562, 416);
            flyers.Size = new Size(118, 159);
            layoutStg.ArtworkDefs.Add(flyers);

            ArtworkDefinition marquees = new ArtworkDefinition();
            marquees.ArtworkType = ArtworkType.Marquee;
            marquees.Location = new Point(75, 89);
            marquees.Size = new Size(331, 77);
            layoutStg.ArtworkDefs.Add(marquees);

            ArtworkDefinition snaps = new ArtworkDefinition();
            snaps.ArtworkType = ArtworkType.Snap;
            snaps.Location = new Point(109, 192);
            snaps.Size = new Size(263, 208);
            layoutStg.ArtworkDefs.Add(snaps);

            ArtworkDefinition controls = new ArtworkDefinition();
            controls.ArtworkType = ArtworkType.ControlPanel;
            controls.Location = new Point(49, 479);
            controls.Size = new Size(387, 119);
            layoutStg.ArtworkDefs.Add(controls);

            layoutStg.GameList.Location = new Point(491, 46);
            layoutStg.GameList.Size = new Size(247, 352);
            layoutStg.SaveTo(@"C:\Users\Mike\Desktop\test\default.layout");
        }

        #endregion

        #region Emulator

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Starts the selected game in the current emulator. </summary>
        ///-------------------------------------------------------------------------------------------------
        private void StartCurrentGame()
        {
            try
            {
                if ((m_currentEmulator != null) && (gameListDisplay.CurrentGame != null))
                {
                    //this.WindowState = FormWindowState.Minimized;

                    Process p = new Process();
                    p.StartInfo.WorkingDirectory = Path.GetDirectoryName(m_currentEmulator.ExecutablePath);
                    p.StartInfo.FileName = m_currentEmulator.ExecutablePath;
                    p.StartInfo.Arguments = gameListDisplay.CurrentGame.Name;
                    p.Exited += gameExited;
                    p.Start(); // TODO: Possibly start in another thread so we can recirect error stream and wait for exit.                    
                }
            }
            catch (Exception err)
            {
                this.WindowState = FormWindowState.Maximized;
                MessageBox.Show(err.Message);
            }
        }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Game exited. </summary>
        /// <param name="sender"> Source of the event. </param>
        /// <param name="e">      Event information. </param>
        ///-------------------------------------------------------------------------------------------------
        private void gameExited(object sender, EventArgs e)
        {
            //this.WindowState = FormWindowState.Maximized;
        }

        #endregion

        #region Layout / Artrok

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Loads layout settings. </summary>
        /// <exception cref="ArgumentNullException"> Thrown when one or more required arguments are null. </exception>
        /// <param name="emulator"> The emulator. </param>
        /// <param name="layout">   The layout. </param>
        ///-------------------------------------------------------------------------------------------------
        private void LoadLayout(Emulator emulator, LayoutStg layout)
        {
            if (emulator == null)
                throw new ArgumentNullException("emulator");

            if (layout == null)
                throw new ArgumentNullException("layout");

            String debugTestPath = Path.Combine("C:\\Users\\Mike\\Desktop\\", emulator.DataFolderName);

            String debugBackgroundPath = Path.Combine(debugTestPath, "default.png");

            // Set background image.
            Image backgroungImage = new Bitmap(debugBackgroundPath);

            // TODO: Eventually compare image size to form size to determine how image should
            // be displayed.
            this.BackgroundImage = backgroungImage;

            if ((BackgroundImage.Width > this.Width) || (BackgroundImage.Height > this.Height))
                BackgroundImageLayout = ImageLayout.None;
            else
                BackgroundImageLayout = ImageLayout.Zoom;

            // Load artwork panes.
            foreach (ArtworkDefinition artworkDefinition in layout.ArtworkDefs)
            {
                // Determine if emulator contains an artwork folder of the appropriate type.
                foreach (KeyValuePair<String, ArtworkType> pair in emulator.ArtworkFolderPaths)
                {
                    if (pair.Value == artworkDefinition.ArtworkType)
                    {
                        PictureBox box = new PictureBox();
                        box.Parent = this;
                        box.Location = artworkDefinition.Location;
                        box.Size = artworkDefinition.Size;
                        box.Tag = pair.Key;
                        box.SizeMode = PictureBoxSizeMode.StretchImage;
                        box.BackColor = Color.Black;

                        m_artworkPictureBoxes.Add(box);
                        break; // Exit inner loop.
                    }
                }
            } // End for each artwork pane.

            // Setup game list.
            gameListDisplay.Location = layout.GameList.Location;
            gameListDisplay.Size = layout.GameList.Size;
            gameListDisplay.LoadSettings(layout.GameList);

            GameListStg debugGameList = new GameListStg(Path.Combine(debugTestPath, "oneper.gamelist"));
            gameListDisplay.AssignList(debugGameList);

            UpdateGameArtwork();
        }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Clears the current artwork. </summary>
        ///-------------------------------------------------------------------------------------------------
        private void ClearGameArtwork()
        {
            if (this.InvokeRequired)
                this.BeginInvoke(new MethodInvoker(delegate { ClearGameArtwork(); }));
            else
            {
                foreach (PictureBox box in m_artworkPictureBoxes)
                    box.ImageLocation = null;
            }
        }

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Displays artwork for specified game. </summary>
        ///-------------------------------------------------------------------------------------------------
        private void UpdateGameArtwork()
        {
            if (this.InvokeRequired)
                this.BeginInvoke(new MethodInvoker(delegate { UpdateGameArtwork(); }));
            else
            {
                try
                {
                    Game game = gameListDisplay.CurrentGame;

                    foreach (PictureBox box in m_artworkPictureBoxes)
                    {
                        String[] matchingArtwork = Directory.GetFiles((String)box.Tag,
                            String.Format("{0}.*", game.Name), SearchOption.TopDirectoryOnly);

                        if ((matchingArtwork.Length < 1) && (!String.IsNullOrWhiteSpace(game.CloneOf)))
                            matchingArtwork = Directory.GetFiles((String)box.Tag,
                                String.Format("{0}.*", game.CloneOf), SearchOption.TopDirectoryOnly);

                        if (matchingArtwork.Length > 0)
                        {
                            if (matchingArtwork[0].EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
                            {
                                // TODO: Add zip support.
                                box.ImageLocation = null;
                            }
                            else
                                box.ImageLocation = matchingArtwork[0];
                        }
                        else
                            box.ImageLocation = null;
                    } // End for each arwork pane.
                }
                catch (Exception err)
                {
                    MessageBox.Show(err.Message);
                }
            }
        }

        #endregion

        #region Control Event Handlers

        ///-------------------------------------------------------------------------------------------------
        /// <summary> Event handler. Called by FormMain for key up events. </summary>
        /// <param name="sender"> Source of the event. </param>
        /// <param name="e">      Key event information. </param>
        ///-------------------------------------------------------------------------------------------------
        private void FormMain_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
                UpdateGameArtwork();
        }

        #endregion
    }
}
